///////////////////////////////////////////////////////////////////////////////
//
// wxFormBuilder - A Visual Dialog Editor for wxWidgets.
// Copyright (C) 2005 José Antonio Hurtado
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Written by
//   José Antonio Hurtado - joseantonio.hurtado@gmail.com
//   Juan Antonio Ortega  - jortegalalmolda@gmail.com
//
///////////////////////////////////////////////////////////////////////////////

#include "logo.xpm"
#include "smiley.xpm"

#include <plugin.h>
#include <ticpp.h>
#include <xrcconv.h>

#include <wx/calctrl.h>
#include <wx/datectrl.h>
#include <wx/dirctrl.h>
#include <wx/grid.h>
#include <wx/html/htmlwin.h>
#include <wx/spinctrl.h>
#include <wx/tglbtn.h>
#include <wx/timectrl.h>
#ifdef USE_MEDIACTRL
#include <wx/mediactrl.h>
#endif
#if wxVERSION_NUMBER >= 2904
// wxPropertyGrid
#include <wx/propgrid/manager.h>
// wxStyledTextCtrl
#include <wx/stc/stc.h>
// wxDataViewCtrl
#include <wx/dataview.h>
// wxRibbonBar
#include <wx/ribbon/buttonbar.h>
#include <wx/ribbon/toolbar.h>
#include <wx/ribbon/gallery.h>
// wxTreeListCtrl
#include <wx/treelist.h>
#endif

#include <wx/clrpicker.h>
#include <wx/filepicker.h>
#include <wx/fontpicker.h>
#include <wx/hyperlink.h>
#include <wx/richtext/richtextctrl.h>
#include <wx/srchctrl.h>

///////////////////////////////////////////////////////////////////////////////

/**
Event handler for events generated by controls in this plugin
*/
class ComponentEvtHandler : public wxEvtHandler
{
private:
	wxWindow* m_window;
	IManager* m_manager;

public:
	ComponentEvtHandler( wxWindow* win, IManager* manager )
	:
	m_window( win ),
	m_manager( manager )
	{
	}

protected:
	void OnGridClick( wxGridEvent& event );
	void OnGridColSize( wxGridSizeEvent& event );
	void OnGridRowSize( wxGridSizeEvent& event );
	void OnColourPickerColourChanged(wxColourPickerEvent& event);
	void OnFontPickerFontChanged(wxFontPickerEvent& event);
	void OnFilePickerFileChanged(wxFileDirPickerEvent& event);
	void OnDirPickerDirChanged(wxFileDirPickerEvent& event);
	void OnText(wxCommandEvent& event);
	void OnGenericDirCtrlExpandItem( wxTreeEvent& event );
#if wxVERSION_NUMBER >= 2904
	// Enable folding for wxStyledTextCtrl
	void OnMarginClick ( wxStyledTextEvent& event );
	void OnRibbonBarPageChanged( wxRibbonBarEvent& event );
#endif
	DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE( ComponentEvtHandler, wxEvtHandler )
	EVT_COLOURPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnColourPickerColourChanged)
	EVT_FONTPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnFontPickerFontChanged)
	EVT_FILEPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnFilePickerFileChanged)
	EVT_DIRPICKER_CHANGED(wxID_ANY, ComponentEvtHandler::OnDirPickerDirChanged)
	EVT_TEXT( wxID_ANY, ComponentEvtHandler::OnText )

	// Grid also seems to ignore clicks
	EVT_GRID_CELL_LEFT_CLICK( ComponentEvtHandler::OnGridClick )
	EVT_GRID_LABEL_LEFT_CLICK( ComponentEvtHandler::OnGridClick )

	EVT_GRID_COL_SIZE( ComponentEvtHandler::OnGridColSize )
	EVT_GRID_ROW_SIZE( ComponentEvtHandler::OnGridRowSize )

#if wxVERSION_NUMBER >= 2904
	EVT_STC_MARGINCLICK(wxID_ANY, ComponentEvtHandler::OnMarginClick)
	EVT_RIBBONBAR_PAGE_CHANGED(wxID_ANY, ComponentEvtHandler::OnRibbonBarPageChanged)
#endif
END_EVENT_TABLE()

/**
Event handler for events generated by wxGenericDirCtrl.
*/
class GenericDirCtrlEvtHandler : public wxEvtHandler
{
public:
	GenericDirCtrlEvtHandler( wxWindow* win, IManager* manager )
	:
	m_window( win ),
	m_manager( manager )
	{
	}

protected:
	void OnGenericDirCtrlLeftClick( wxMouseEvent& event );
	DECLARE_EVENT_TABLE()
private:
	wxWindow* m_window;
	IManager* m_manager;

};

BEGIN_EVENT_TABLE( GenericDirCtrlEvtHandler, wxEvtHandler )
	// GenericDirCtrl also seems to ignore clicks
	EVT_LEFT_DOWN( GenericDirCtrlEvtHandler::OnGenericDirCtrlLeftClick )
END_EVENT_TABLE()

///////////////////////////////////////////////////////////////////////////////

class CalendarCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		return new wxCalendarCtrl((wxWindow *)parent, wxID_ANY,
			wxDefaultDateTime,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
	}

	ticpp::Element* ExportToXrc(IObject *obj) override
	{
		ObjectToXrcFilter xrc(obj, _("wxCalendarCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxCalendarCtrl"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class DatePickerCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		return new wxDatePickerCtrl((wxWindow *)parent, wxID_ANY,
			wxDefaultDateTime,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxDatePickerCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxDatePickerCtrl"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class TimePickerCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		return new wxTimePickerCtrl( ( wxWindow * )parent, wxID_ANY,
									 wxDefaultDateTime,
									 obj->GetPropertyAsPoint( _( "pos" ) ),
									 obj->GetPropertyAsSize( _( "size" ) ),
									 obj->GetPropertyAsInteger( _( "style" ) ) | obj->GetPropertyAsInteger( _( "window_style" ) ) );
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc( obj, _( "wxTimePickerCtrl" ), obj->GetPropertyAsString( _( "name" ) ) );
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter( xrcObj, _( "wxTimePickerCtrl" ) );
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};




class RichTextCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRichTextCtrl* richText = new wxRichTextCtrl( 	(wxWindow*)parent,
															wxID_ANY,
															wxEmptyString,
															obj->GetPropertyAsPoint(_("pos")),
															obj->GetPropertyAsSize(_("size")),
															obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		wxFont textFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
		wxFont boldFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
		wxFont italicFont = wxFont(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_NORMAL);

		wxFont font(12, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);

		wxRichTextCtrl& r = *richText;
		r.SetFont(font);
		r.BeginSuppressUndo();

		r.BeginParagraphSpacing(0, 20);

		r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
		r.BeginBold();

		r.BeginFontSize(14);
		r.WriteText(wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images"));
		r.EndFontSize();
		r.Newline();

		r.BeginItalic();
		r.WriteText(wxT("by Julian Smart"));
		r.EndItalic();

		r.EndBold();

		r.Newline();
		r.WriteImage(wxBitmap(logo_xpm));

		r.EndAlignment();

		r.Newline();

		r.WriteText(wxT("What can you do with this thing? "));
		r.WriteImage(wxBitmap(smiley_xpm));
		r.WriteText(wxT(" Well, you can change text "));

		r.BeginTextColour(wxColour(255, 0, 0));
		r.WriteText(wxT("colour, like this red bit."));
		r.EndTextColour();

		r.BeginTextColour(wxColour(0, 0, 255));
		r.WriteText(wxT(" And this blue bit."));
		r.EndTextColour();

		r.WriteText(wxT(" Naturally you can make things "));
		r.BeginBold();
		r.WriteText(wxT("bold "));
		r.EndBold();
		r.BeginItalic();
		r.WriteText(wxT("or italic "));
		r.EndItalic();
		r.BeginUnderline();
		r.WriteText(wxT("or underlined."));
		r.EndUnderline();

		r.BeginFontSize(14);
		r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
		r.EndFontSize();

		r.WriteText(wxT(" Next we'll show an indented paragraph."));

		r.BeginLeftIndent(60);
		r.Newline();

		r.WriteText(wxT("Indented paragraph."));
		r.EndLeftIndent();

		r.Newline();

		r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));

		r.BeginLeftIndent(100, -40);
		r.Newline();

		r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter."));
		r.EndLeftIndent();

		r.Newline();

		r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));

		r.BeginNumberedBullet(1, 100, 60);
		r.Newline();

		r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later."));
		r.EndNumberedBullet();

		r.BeginNumberedBullet(2, 100, 60);
		r.Newline();

		r.WriteText(wxT("This is my second item."));
		r.EndNumberedBullet();

		r.Newline();

		r.WriteText(wxT("The following paragraph is right-indented:"));

		r.BeginRightIndent(200);
		r.Newline();

		r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
		r.EndRightIndent();

		r.Newline();

		wxArrayInt tabs;
		tabs.Add(400);
		tabs.Add(600);
		tabs.Add(800);
		tabs.Add(1000);
		wxTextAttrEx attr;
		attr.SetFlags(wxTEXT_ATTR_TABS);
		attr.SetTabs(tabs);
		r.SetDefaultStyle(attr);

		r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));

		r.Newline();
		r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));

		r.BeginSymbolBullet(wxT('*'), 100, 60);
		r.Newline();
		r.WriteText(wxT("Compatibility with wxTextCtrl API"));
		r.EndSymbolBullet();

		r.WriteText(wxT("\nNote: this content was generated programmatically and copied from the sample. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!"));

		r.EndSuppressUndo();

		return richText;
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("unknown"), obj->GetPropertyAsString(_("name")));
		//xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxRichTextCtrl"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class HtmlWindowComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxHtmlWindow *hw = new wxHtmlWindow((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		wxString dummy_page(
			wxT("<b>wxHtmlWindow</b><br />")
			wxT("This is a dummy page.</body></html>"));

		hw->SetPage(dummy_page);

		return hw;
	}

	ticpp::Element* ExportToXrc(IObject *obj) override
	{
		ObjectToXrcFilter xrc(obj, _("wxHtmlWindow"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxHtmlWindow"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};



class ToggleButtonComponent : public ComponentBase, public wxEvtHandler
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxString label = obj->GetPropertyAsString( _("label") );
		wxToggleButton* button = new wxToggleButton((wxWindow *)parent, wxID_ANY,
			label,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

#if wxCHECK_VERSION( 2, 9, 2 )
		if (obj->GetPropertyAsInteger(_("markup")) != 0) {
			button->SetLabelMarkup(label);
		}
#endif

		if (!obj->IsNull(_("bitmap"))) {
			button->SetBitmap(obj->GetPropertyAsBitmap(_("bitmap")));
		}

		if (!obj->IsNull(_("disabled"))) {
			button->SetBitmapDisabled(obj->GetPropertyAsBitmap(_("disabled")));
		}

		if (!obj->IsNull(_("pressed"))) {
			button->SetBitmapPressed(obj->GetPropertyAsBitmap(_("pressed")));
		}

		if (!obj->IsNull(_("focus"))) {
			button->SetBitmapFocus(obj->GetPropertyAsBitmap(_("focus")));
		}

		if (!obj->IsNull(_("current"))) {
			button->SetBitmapCurrent(obj->GetPropertyAsBitmap(_("current")));
		}

		if (!obj->IsNull(_("position"))) {
			button->SetBitmapPosition(
			    static_cast<wxDirection>(obj->GetPropertyAsInteger(_("position"))));
		}

		if (!obj->IsNull(_("margins"))) {
			button->SetBitmapMargins(obj->GetPropertyAsSize(_("margins")));
		}

		button->SetValue((obj->GetPropertyAsInteger(_("value")) != 0));
		button->Connect( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler( ToggleButtonComponent::OnToggle ), NULL, this );
		return button;
	}

	void OnToggle( wxCommandEvent& event )
	{
		wxToggleButton* window = dynamic_cast< wxToggleButton* >( event.GetEventObject() );
		if ( 0 != window )
		{
			wxString value;
			value.Printf( wxT("%i"), window->GetValue() ? 1 : 0 );
			GetManager()->ModifyProperty( window, _("value"), value );
			window->SetFocus();
		}
	}


	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxToggleButton"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("label"),_("label"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("markup"), _("markup"), XRC_TYPE_BOOL);
		xrc.AddProperty(_("bitmap"), _("bitmap"), XRC_TYPE_BITMAP);
		if (!obj->IsNull(_("disabled"))) {
			xrc.AddProperty(_("disabled"), _("disabled"), XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("pressed"))) {
			xrc.AddProperty(_("pressed"), _("pressed"), XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("focus"))) {
			xrc.AddProperty(_("focus"), _("focus"), XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("current"))) {
			xrc.AddProperty(_("current"), _("current"), XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("position"))) {
			xrc.AddProperty(_("position"), _("position"), XRC_TYPE_TEXT);
		}
		if (!obj->IsNull(_("margins"))) {
			xrc.AddProperty(_("margins"), _("margins"), XRC_TYPE_SIZE);
		}
		xrc.AddProperty(_("value"),_("checked"), XRC_TYPE_BOOL);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxToggleButton"));
		filter.AddWindowProperties();
		filter.AddProperty(_("label"),_("label"),XRC_TYPE_TEXT);
		filter.AddProperty(_("markup"), _("markup"), XRC_TYPE_BOOL);
		filter.AddProperty(_("bitmap"), _("bitmap"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("disabled"), _("disabled"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("pressed"), _("pressed"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("focus"), _("focus"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("current"), _("current"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("position"), _("position"), XRC_TYPE_TEXT);
		filter.AddProperty(_("margins"), _("margins"), XRC_TYPE_SIZE);
		filter.AddProperty(_("checked"),_("value"), XRC_TYPE_BOOL);
		return filter.GetXfbObject();
	}
};

class BitmapToggleButtonComponent : public ComponentBase, public wxEvtHandler
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxBitmapToggleButton* button = new wxBitmapToggleButton((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsBitmap(_("bitmap")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

#if wxCHECK_VERSION( 2, 9, 2 )
		// To stay in sync what the generator templates do apply the markup label here as well
		if (obj->GetPropertyAsInteger(_("markup")) != 0) {
			button->SetLabelMarkup(obj->GetPropertyAsString(_("label")));
		}
#endif

		if (!obj->IsNull(_("disabled")))
		{
			button->SetBitmapDisabled( obj->GetPropertyAsBitmap( _("disabled") ) );
		}

		if (!obj->IsNull(_("pressed"))) {
			button->SetBitmapPressed(obj->GetPropertyAsBitmap(_("pressed")));
		}

		if (!obj->IsNull(_("focus")))
		{
			button->SetBitmapFocus( obj->GetPropertyAsBitmap( _("focus") ) );
		}

		if (!obj->IsNull(_("current"))) {
			button->SetBitmapCurrent(obj->GetPropertyAsBitmap(_("current")));
		}

		if (!obj->IsNull(_("position"))) {
			button->SetBitmapPosition(
			    static_cast<wxDirection>(obj->GetPropertyAsInteger(_("position"))));
		}

		if (!obj->IsNull(_("margins"))) {
			button->SetBitmapMargins(obj->GetPropertyAsSize(_("margins")));
		}

		button->SetValue( ( obj->GetPropertyAsInteger(_("value")) != 0 ) );
		button->Connect( wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler( ToggleButtonComponent::OnToggle ), NULL, this );

		return button;
	}

	void OnToggle(wxCommandEvent& event)
	{
		wxBitmapToggleButton* window = dynamic_cast< wxBitmapToggleButton* >( event.GetEventObject() );
		if ( 0 != window )
		{
			wxString value;
			value.Printf( wxT("%i"), window->GetValue() ? 1 : 0 );
			GetManager()->ModifyProperty( window, _("value"), value );
			window->SetFocus();
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxBitmapToggleButton"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("bitmap"),_("bitmap"),XRC_TYPE_BITMAP);
		if ( !obj->IsNull( _("disabled") ) )
		{
			xrc.AddProperty(_("disabled"),_("disabled"),XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("pressed"))) {
			xrc.AddProperty(_("pressed"), _("pressed"), XRC_TYPE_BITMAP);
		}
		if ( !obj->IsNull( _("focus") ) )
		{
			xrc.AddProperty(_("focus"),_("focus"),XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("current"))) {
			xrc.AddProperty(_("current"), _("current"), XRC_TYPE_BITMAP);
		}
		if (!obj->IsNull(_("position"))) {
			xrc.AddProperty(_("position"), _("position"), XRC_TYPE_TEXT);
		}
		if (!obj->IsNull(_("margins"))) {
			xrc.AddProperty(_("margins"), _("margins"), XRC_TYPE_SIZE);
		}
		xrc.AddProperty(_("value"),_("checked"), XRC_TYPE_BOOL);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxBitmapToggleButton"));
		filter.AddWindowProperties();
		filter.AddProperty(_("bitmap"),_("bitmap"),XRC_TYPE_BITMAP);
		filter.AddProperty(_("disabled"),_("disabled"),XRC_TYPE_BITMAP);
		filter.AddProperty(_("pressed"), _("pressed"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("focus"),_("focus"),XRC_TYPE_BITMAP);
		filter.AddProperty(_("current"), _("current"), XRC_TYPE_BITMAP);
		filter.AddProperty(_("position"), _("position"), XRC_TYPE_TEXT);
		filter.AddProperty(_("margins"), _("margins"), XRC_TYPE_SIZE);
		filter.AddProperty(_("checked"),_("value"), XRC_TYPE_BOOL);
		return filter.GetXfbObject();
	}

};

class TreeCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		int style = obj->GetPropertyAsInteger(_("style"));
		wxTreeCtrl *tc = new wxTreeCtrl((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			style | obj->GetPropertyAsInteger(_("window_style")));

		// dummy nodes
		wxTreeItemId root = tc->AddRoot(wxT("root node"));
		wxTreeItemId node1 = tc->AppendItem(root,wxT("node1"));
		wxTreeItemId node2 = tc->AppendItem(root,wxT("node2"));
		wxTreeItemId node3 = tc->AppendItem(node2,wxT("node3"));
		if ( ( style & wxTR_HIDE_ROOT ) == 0 )
		{
			tc->Expand(root);
		}
		tc->Expand(node1);
		tc->Expand(node2);
		tc->Expand(node3);

		return tc;
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxTreeCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxTreeCtrl"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class ScrollBarComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxScrollBar *sb = new wxScrollBar((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		sb->SetScrollbar(obj->GetPropertyAsInteger(_T("value")),
			obj->GetPropertyAsInteger(_T("thumbsize")),
			obj->GetPropertyAsInteger(_T("range")),
			obj->GetPropertyAsInteger(_T("pagesize")));
		return sb;
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxScrollBar"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("value"), _("value"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("thumbsize"), _("thumbsize"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("range"), _("range"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("pagesize"), _("pagesize"), XRC_TYPE_INTEGER);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxScrollBar"));
		filter.AddWindowProperties();
		filter.AddProperty(_("value"), _("value"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("thumbsize"), _("thumbsize"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("range"), _("range"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("pagesize"), _("pagesize"), XRC_TYPE_INTEGER);
		return filter.GetXfbObject();
	}
};

class SpinCtrlComponent : public ComponentBase, public wxEvtHandler
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		int max = obj->GetPropertyAsInteger(_("max"));
		int min = obj->GetPropertyAsInteger(_("min"));
		wxSpinCtrl* window = new wxSpinCtrl((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsString(_("value")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")),
			min < max ? min : max,
			max,
			obj->GetPropertyAsInteger(_("initial")));

		window->Connect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( SpinCtrlComponent::OnSpin ), NULL, this );
		return window;
	}

	void OnSpin( wxSpinEvent& event )
	{
		wxSpinCtrl* window = dynamic_cast< wxSpinCtrl* >( event.GetEventObject() );
		if ( 0 != window )
		{
			wxString value;
			value.Printf( wxT("%i"), window->GetValue() );
			GetManager()->ModifyProperty( window, _("initial"), value );
			window->SetFocus();
		}
	}

	void Cleanup(wxObject* obj) override {
		wxSpinCtrl* window = dynamic_cast< wxSpinCtrl* >( obj );
		if ( 0 != window )
		{
			window->Disconnect( wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler( SpinCtrlComponent::OnSpin ), NULL, this );
		}
		ComponentBase::Cleanup( obj );
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxSpinCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("initial"),_("value"), XRC_TYPE_TEXT);
		xrc.AddProperty(_("min"),_("min"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("max"),_("max"), XRC_TYPE_INTEGER);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxSpinCtrl"));
		filter.AddWindowProperties();
		filter.AddProperty(_("value"),_("value"), XRC_TYPE_TEXT);
		filter.AddProperty(_("value"),_("initial"), XRC_TYPE_TEXT);
		filter.AddProperty(_("min"),_("min"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("max"),_("max"), XRC_TYPE_INTEGER);

		return filter.GetXfbObject();
	}
};

class SpinCtrlDoubleComponent : public ComponentBase, public wxEvtHandler
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxSpinCtrlDouble* window = new wxSpinCtrlDouble((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsString(_("value")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")),
			obj->GetPropertyAsFloat(_("min")),
			obj->GetPropertyAsFloat(_("max")),
			obj->GetPropertyAsFloat(_("initial")),
			obj->GetPropertyAsFloat(_("inc")));

		window->SetDigits(obj->GetPropertyAsInteger(_("digits")));

		window->Connect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinEventHandler( SpinCtrlDoubleComponent::OnSpin ), NULL, this );
		return window;
	}

	void OnSpin( wxSpinEvent& event )
	{
		wxSpinCtrlDouble* window = dynamic_cast< wxSpinCtrlDouble* >( event.GetEventObject() );
		if ( 0 != window )
		{
			wxString value;
			value.Printf( wxT("%f"), window->GetValue() );
			GetManager()->ModifyProperty( window, _("initial"), value );
			window->SetFocus();
		}
	}

	void Cleanup(wxObject* obj) override {
		wxSpinCtrlDouble* window = dynamic_cast< wxSpinCtrlDouble* >( obj );
		if ( 0 != window )
		{
			window->Disconnect( wxEVT_COMMAND_SPINCTRLDOUBLE_UPDATED, wxSpinEventHandler( SpinCtrlDoubleComponent::OnSpin ), NULL, this );
		}
		ComponentBase::Cleanup( obj );
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxSpinCtrlDouble"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("initial"),_("value"), XRC_TYPE_TEXT);
		xrc.AddProperty(_("min"),_("min"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("max"),_("max"), XRC_TYPE_INTEGER);
		xrc.AddProperty(_("inc"),_("inc"), XRC_TYPE_FLOAT);
		xrc.AddProperty(_("digits"), _("digits"), XRC_TYPE_INTEGER);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxSpinCtrl"));
		filter.AddWindowProperties();
		filter.AddProperty(_("value"),_("value"), XRC_TYPE_TEXT);
		filter.AddProperty(_("value"),_("initial"), XRC_TYPE_TEXT);
		filter.AddProperty(_("min"),_("min"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("max"),_("max"), XRC_TYPE_INTEGER);
		filter.AddProperty(_("inc"),_("inc"), XRC_TYPE_FLOAT);
		filter.AddProperty(_("digits"), _("digits"), XRC_TYPE_INTEGER);

		return filter.GetXfbObject();
	}
};

class SpinButtonComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		return new wxSpinButton((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxSpinButton"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxSpinButton"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class CheckListBoxComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxArrayString choices (obj->GetPropertyAsArrayString(_("choices")));
		wxCheckListBox *cl =
			new wxCheckListBox((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			choices,
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		return cl;
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxCheckListBox"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("choices"), _("content"), XRC_TYPE_STRINGLIST);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxCheckListBox"));
		filter.AddWindowProperties();
		filter.AddProperty(_("content"), _("choices"), XRC_TYPE_STRINGLIST);
		return filter.GetXfbObject();
	}
};

class GridComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxGrid *grid = new wxGrid((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("window_style")));

		grid->CreateGrid(
			obj->GetPropertyAsInteger(_("rows")),
			obj->GetPropertyAsInteger(_("cols")));

		grid->EnableDragColMove( obj->GetPropertyAsInteger( _("drag_col_move") ) != 0 );
		grid->EnableDragColSize( obj->GetPropertyAsInteger( _("drag_col_size") ) != 0 );
		grid->EnableDragGridSize( obj->GetPropertyAsInteger( _("drag_grid_size") ) != 0 );
		grid->EnableDragRowSize( obj->GetPropertyAsInteger( _("drag_row_size") ) != 0 );
		grid->EnableEditing( obj->GetPropertyAsInteger( _("editing") ) != 0 );
		grid->EnableGridLines( obj->GetPropertyAsInteger( _("grid_lines") ) != 0 );
		if ( !obj->IsNull( _("grid_line_color") ) )
		{
			grid->SetGridLineColour( obj->GetPropertyAsColour( _("grid_line_color") ) );
		}
		grid->SetMargins( obj->GetPropertyAsInteger( _("margin_width") ), obj->GetPropertyAsInteger( _("margin_height") ) );

		// Label Properties
		grid->SetColLabelAlignment( obj->GetPropertyAsInteger( _("col_label_horiz_alignment") ), obj->GetPropertyAsInteger( _("col_label_vert_alignment") ) );
		grid->SetColLabelSize( obj->GetPropertyAsInteger( _("col_label_size") ) );

		wxArrayString columnLabels = obj->GetPropertyAsArrayString( _("col_label_values") );
		for ( int i = 0; i < (int)columnLabels.size() && i < grid->GetNumberCols(); ++i )
		{
			grid->SetColLabelValue( i, columnLabels[i] );
		}

		wxArrayInt columnSizes = obj->GetPropertyAsArrayInt( _("column_sizes") );
		for ( int i = 0; i < (int)columnSizes.size() && i < grid->GetNumberCols(); ++i )
		{
			grid->SetColSize( i, columnSizes[i] );
		}

		grid->SetRowLabelAlignment( obj->GetPropertyAsInteger( _("row_label_horiz_alignment") ), obj->GetPropertyAsInteger( _("row_label_vert_alignment") ) );
		grid->SetRowLabelSize( obj->GetPropertyAsInteger( _("row_label_size") ) );

		wxArrayString rowLabels = obj->GetPropertyAsArrayString( _("row_label_values") );
		for ( int i = 0; i < (int)rowLabels.size() && i < grid->GetNumberRows(); ++i )
		{
			grid->SetRowLabelValue( i, rowLabels[i] );
		}

		wxArrayInt rowSizes = obj->GetPropertyAsArrayInt( _("row_sizes") );
		for ( int i = 0; i < (int)rowSizes.size() && i < grid->GetNumberRows(); ++i )
		{
			grid->SetRowSize( i, rowSizes[i] );
		}

		if ( !obj->IsNull( _("label_bg") ) )
		{
			grid->SetLabelBackgroundColour( obj->GetPropertyAsColour( _("label_bg") ) );
		}
		if ( !obj->IsNull( _("label_text") ) )
		{
			grid->SetLabelTextColour( obj->GetPropertyAsColour( _("label_text") ) );
		}
		if ( !obj->IsNull( _("label_font") ) )
		{
			grid->SetLabelFont( obj->GetPropertyAsFont( _("label_font") ) );
		}

		// Default Cell Properties
		grid->SetDefaultCellAlignment( obj->GetPropertyAsInteger( _("cell_horiz_alignment") ), obj->GetPropertyAsInteger( _("cell_vert_alignment") ) );

		if ( !obj->IsNull( _("cell_bg") ) )
		{
			grid->SetDefaultCellBackgroundColour( obj->GetPropertyAsColour( _("cell_bg") ) );
		}
		if ( !obj->IsNull( _("cell_text") ) )
		{
			grid->SetDefaultCellTextColour( obj->GetPropertyAsColour( _("cell_text") ) );
		}
		if ( !obj->IsNull( _("cell_font") ) )
		{
			grid->SetDefaultCellFont( obj->GetPropertyAsFont( _("cell_font") ) );
		}

		// Example Cell Values
		for ( int col = 0; col < grid->GetNumberCols(); ++col )
		{
			for ( int row = 0; row < grid->GetNumberRows(); ++row )
			{
				grid->SetCellValue( row, col, grid->GetColLabelValue( col ) + wxT("-") + grid->GetRowLabelValue( row ) );
			}
		}

		if ( obj->GetPropertyAsInteger( _("autosize_rows") ) != 0 )
		{
			grid->AutoSizeRows();
		}
		if ( obj->GetPropertyAsInteger( _("autosize_cols") ) != 0 )
		{
			grid->AutoSizeColumns();
		}

		grid->PushEventHandler( new ComponentEvtHandler( grid, GetManager() ) );

		return grid;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxGrid);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxGrid"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxGrid"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void ComponentEvtHandler::OnGridClick( wxGridEvent& event )
{
	m_manager->SelectObject( m_window );
	event.Skip();
}

void ComponentEvtHandler::OnGridColSize( wxGridSizeEvent& )
{
	wxGrid* grid = wxDynamicCast( m_window, wxGrid );
	if ( NULL == grid )
	{
		return;
	}

	wxString sizes;
	for ( int i = 0; i < grid->GetNumberCols(); ++i )
	{
		sizes += wxString::Format( wxT("%i,"), grid->GetColSize( i ) );
	}
	sizes = sizes.substr( 0, sizes.length() - 1 );

	m_manager->ModifyProperty( m_window, _("column_sizes"), sizes, true );
}

void ComponentEvtHandler::OnGridRowSize( wxGridSizeEvent& )
{
	wxGrid* grid = wxDynamicCast( m_window, wxGrid );
	if ( NULL == grid )
	{
		return;
	}

	wxString sizes;
	for ( int i = 0; i < grid->GetNumberRows(); ++i )
	{
		sizes += wxString::Format( wxT("%i,"), grid->GetRowSize( i ) );
	}
	sizes = sizes.substr( 0, sizes.length() - 1 );

	m_manager->ModifyProperty( m_window, _("row_sizes"), sizes, true );
}

class PickerComponentBase : public ComponentBase, public wxEvtHandler
{
public:
	void OnLeftClick( wxMouseEvent& event )
	{
		wxWindow* window = dynamic_cast< wxWindow* >( event.GetEventObject() );
		wxPickerBase* picker = dynamic_cast< wxPickerBase* >( window->GetParent() );
		if ( 0 != picker )
		{
			if ( !GetManager()->SelectObject( picker ) )
			{
				event.Skip();
			}
		}
	}

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxPickerBase* picker = dynamic_cast< wxPickerBase* >( wxobject );
		if ( picker != 0 )
		{
			picker->GetPickerCtrl()->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PickerComponentBase::OnLeftClick ), NULL, this );

			wxTextCtrl* text = picker->GetTextCtrl();
			if ( 0 != text )
			{
				text->Connect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PickerComponentBase::OnLeftClick ), NULL, this );
			}
		}
	}

	void Cleanup(wxObject* obj) override {
		wxPickerBase* picker = dynamic_cast< wxPickerBase* >( obj );
		if ( picker != 0 )
		{
			picker->GetPickerCtrl()->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PickerComponentBase::OnLeftClick ), NULL, this );

			wxTextCtrl* text = picker->GetTextCtrl();
			if ( 0 != text )
			{
				text->Disconnect( wxEVT_LEFT_DOWN, wxMouseEventHandler( PickerComponentBase::OnLeftClick ), NULL, this );
			}
		}
		ComponentBase::Cleanup( obj );
	}
};

class ColourPickerComponent : public PickerComponentBase
{
private:

public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxColourPickerCtrl* colourpicker = new wxColourPickerCtrl(
			(wxWindow*)parent,
			obj->GetPropertyAsInteger(_("id")),
			obj->GetPropertyAsColour(_("colour")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))
			);

		colourpicker->PushEventHandler( new ComponentEvtHandler( colourpicker, GetManager() ) );
		return colourpicker;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxColourPickerCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxColourPickerCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddProperty(_("colour"),_("value"),XRC_TYPE_COLOUR);
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxColourPickerCtrl"));
		filter.AddProperty(_("value"),_("colour"),XRC_TYPE_COLOUR);
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void ComponentEvtHandler::OnColourPickerColourChanged( wxColourPickerEvent& )
{
	wxColourPickerCtrl* window = wxDynamicCast( m_window, wxColourPickerCtrl );
	if ( window != NULL )
	{
		wxColour colour = window->GetColour();
		m_manager->ModifyProperty( window, _("colour"), wxString::Format(wxT("%d,%d,%d"),colour.Red(),colour.Green(),colour.Blue())  );
	}
}

class FontPickerComponent : public PickerComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxFontPickerCtrl* picker = new wxFontPickerCtrl(
			(wxWindow*)parent,
			obj->GetPropertyAsInteger(_("id")),
			obj->GetPropertyAsFont(_("value")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))
			);

		if ( !obj->IsNull( _("max_point_size") ) )
		{
			picker->SetMaxPointSize( obj->GetPropertyAsInteger( _("max_point_size") ) );
		}

		picker->PushEventHandler( new ComponentEvtHandler( picker, GetManager() ) );
		return picker;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxFontPickerCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxFontPickerCtrl"), obj->GetPropertyAsString(_("name")));
		if ( !obj->IsNull( _("value") ) )
		{
			xrc.AddProperty(_("value"),_("value"),XRC_TYPE_FONT);
		}
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxFontPickerCtrl"));
		filter.AddProperty(_("value"),_("value"),XRC_TYPE_FONT);
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void ComponentEvtHandler::OnFontPickerFontChanged( wxFontPickerEvent& )
{
	wxFontPickerCtrl* window = wxDynamicCast( m_window, wxFontPickerCtrl );
	if ( window != NULL )
	{
		wxFont font = window->GetSelectedFont();
		m_manager->ModifyProperty( window, _("value"), wxString::Format( wxT("%s,%d,%d,%d"), font.GetFaceName().c_str(), font.GetStyle(), font.GetWeight(), font.GetPointSize() ) );
	}
}

class FilePickerComponent : public PickerComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxFilePickerCtrl* picker = new wxFilePickerCtrl(
			(wxWindow*)parent,
			obj->GetPropertyAsInteger(_("id")),
			obj->GetPropertyAsString(_("value")),
			obj->GetPropertyAsString(_("message")),
			obj->GetPropertyAsString(_("wildcard")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))
			);

		picker->PushEventHandler( new ComponentEvtHandler( picker, GetManager() ) );
		return picker;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxFilePickerCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxFilePickerCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddProperty(_("value"),_("value"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("message"),_("message"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("wildcard"),_("wildcard"),XRC_TYPE_TEXT);
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxFilePickerCtrl"));
		filter.AddProperty(_("value"),_("value"),XRC_TYPE_FONT);
		filter.AddProperty(_("message"),_("message"),XRC_TYPE_TEXT);
		filter.AddProperty(_("wildcard"),_("wildcard"),XRC_TYPE_TEXT);
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void ComponentEvtHandler::OnFilePickerFileChanged( wxFileDirPickerEvent& )
{
	wxFilePickerCtrl* window = wxDynamicCast( m_window, wxFilePickerCtrl );
	if ( window != NULL )
	{
		m_manager->ModifyProperty( window, _("value"), window->GetPath() );
	}
}

class DirPickerComponent : public PickerComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxDirPickerCtrl* picker = new wxDirPickerCtrl(
			(wxWindow*)parent,
			obj->GetPropertyAsInteger(_("id")),
			obj->GetPropertyAsString(_("value")),
			obj->GetPropertyAsString(_("message")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))
			);

		picker->PushEventHandler( new ComponentEvtHandler( picker, GetManager() ) );
		return picker;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxDirPickerCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxDirPickerCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddProperty(_("value"),_("value"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("message"),_("message"),XRC_TYPE_TEXT);
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxDirPickerCtrl"));
		filter.AddProperty(_("value"),_("value"),XRC_TYPE_FONT);
		filter.AddProperty(_("message"),_("message"),XRC_TYPE_TEXT);
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void ComponentEvtHandler::OnDirPickerDirChanged( wxFileDirPickerEvent& )
{
	wxDirPickerCtrl* window = wxDynamicCast( m_window, wxDirPickerCtrl );
	if ( window != NULL )
	{
		m_manager->ModifyProperty( window, _("value"), window->GetPath() );
	}
}

class HyperlinkComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxHyperlinkCtrl* ctrl = new wxHyperlinkCtrl(
			(wxWindow*)parent, wxID_ANY,
			obj->GetPropertyAsString(_("label")),
			obj->GetPropertyAsString(_("url")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))
			);

		if ( !obj->IsNull( _("hover_color") ) )
		{
			ctrl->SetHoverColour( obj->GetPropertyAsColour( _("hover_color") ) );
		}
		if ( !obj->IsNull( _("normal_color") ) )
		{
			ctrl->SetNormalColour( obj->GetPropertyAsColour( _("normal_color") ) );
		}
		if ( !obj->IsNull( _("visited_color") ) )
		{
			ctrl->SetVisitedColour( obj->GetPropertyAsColour( _("visited_color") ) );
		}

		return ctrl;
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxHyperlinkCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddProperty(_("label"),_("label"),XRC_TYPE_TEXT);
		xrc.AddPropertyValue(_("url"), obj->GetPropertyAsString(_("url")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxHyperlinkCtrl"));
		filter.AddProperty(_("label"),_("label"),XRC_TYPE_TEXT);

		try
		{
			ticpp::Element *urlElement = xrcObj->FirstChildElement("url");
			wxString url(urlElement->GetText().c_str(), wxConvUTF8);

			filter.AddPropertyValue(_("url"), url);
		}
		catch(ticpp::Exception&)
		{
		}

		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

class GenericDirCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxGenericDirCtrl* ctrl = new wxGenericDirCtrl(
			(wxWindow*)parent,
			wxID_ANY,
			obj->GetPropertyAsString(_("defaultfolder")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")),
			obj->GetPropertyAsString(_("filter")),
			obj->GetPropertyAsInteger(_("defaultfilter"))
			);

		ctrl->ShowHidden( obj->GetPropertyAsInteger( _("show_hidden") ) != 0 );
		ctrl->GetTreeCtrl()->PushEventHandler( new GenericDirCtrlEvtHandler( ctrl, GetManager() ) );
		return ctrl;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxGenericDirCtrl);
		if (window)
		{
			window->GetTreeCtrl()->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxGenericDirCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddProperty(_("defaultfolder"),_("defaultfolder"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("filter"),_("filter"),XRC_TYPE_TEXT);
		xrc.AddProperty(_("defaultfilter"),_("defaultfilter"),XRC_TYPE_INTEGER);
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxGenericDirCtrl"));
		filter.AddProperty(_("defaultfolder"),_("defaultfolder"),XRC_TYPE_TEXT);
		filter.AddProperty(_("filter"),_("filter"),XRC_TYPE_TEXT);
		filter.AddProperty(_("defaultfilter"),_("defaultfilter"),XRC_TYPE_INTEGER);
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};

void GenericDirCtrlEvtHandler::OnGenericDirCtrlLeftClick( wxMouseEvent& event )
{
	m_manager->SelectObject( m_window );
	event.Skip();
}

class CustomControlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* /*obj*/, wxObject* parent) override {
		return new wxPanel((wxWindow *)parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, obj->GetPropertyAsString(_("class")), obj->GetPropertyAsString(_("name")));
		return xrc.GetXrcObject();
	}
};

class SearchCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxSearchCtrl* sc = new wxSearchCtrl((wxWindow *)parent, wxID_ANY,
			obj->GetPropertyAsString(_("value")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		if ( !obj->IsNull( _("search_button") ) )
		{
			sc->ShowSearchButton(obj->GetPropertyAsInteger(_("search_button")) != 0);
		}

		if ( !obj->IsNull( _("cancel_button") ) )
		{
			sc->ShowCancelButton(obj->GetPropertyAsInteger(_("cancel_button")) != 0);
		}

		sc->PushEventHandler( new ComponentEvtHandler( sc, GetManager() ) );

		return sc;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxSearchCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxSearchCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		xrc.AddProperty(_("value"),_("value"),XRC_TYPE_TEXT);
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxSearchCtrl"));
		filter.AddWindowProperties();
		filter.AddProperty(_("value"),_("value"),XRC_TYPE_TEXT);
		return filter.GetXfbObject();
	}

};

void ComponentEvtHandler::OnText( wxCommandEvent& event)
{
	wxSearchCtrl* sc = wxDynamicCast( m_window, wxSearchCtrl );
	if ( sc != NULL )
	{
		m_manager->ModifyProperty( m_window, _("value"), sc->GetValue() );
		sc->SetInsertionPointEnd();
		sc->SetFocus();
	}

	event.Skip();
}

#ifdef USE_MEDIACTRL
class MediaCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxMediaCtrl* mc = new wxMediaCtrl((wxWindow *)parent, wxID_ANY, wxT(""),obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		if ( !obj->IsNull( _("file") ) )
		{
			if( mc->Load( obj->GetPropertyAsString( _("file") ) ) )
			{
				if (!obj->IsNull( _("playback_rate"))) mc->SetPlaybackRate(obj->GetPropertyAsFloat(_("playback_rate")));
				if (!obj->IsNull( _("volume")) && (obj->GetPropertyAsFloat(_("volume"))>=0)&&(obj->GetPropertyAsFloat(_("volume"))<=1))
						mc->SetPlaybackRate(obj->GetPropertyAsFloat(_("volume")));
				if (!obj->IsNull(_("player_controls")))
				{
					if(  obj->GetPropertyAsString( _("player_controls") ) == wxT("STEP") )	mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_STEP);
					if(  obj->GetPropertyAsString( _("player_controls") ) == wxT("VOLUME") )	mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_VOLUME);
					if(  obj->GetPropertyAsString( _("player_controls") ) == wxT("DEFAULT") )	mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_DEFAULT);
					if(  obj->GetPropertyAsString( _("player_controls") ) == wxT("NONE") )	mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_NONE);

				}

				if ( !obj->IsNull( _("play") ) && ( obj->GetPropertyAsInteger( _("play") ) == 1 ) ) mc->Play();
				else
					mc->Stop();

				//GetManager()->ModifyProperty( m_window, wxT("size"), mc->GetBestSize() );
			}
		}

		if(!obj->IsNull(_("style"))) mc->ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_STEP);

		mc->PushEventHandler( new ComponentEvtHandler( mc, GetManager() ) );

		return mc;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxMediaCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	ticpp::Element* ExportToXrc(IObject* obj) override {
		ObjectToXrcFilter xrc(obj, _("wxMediaCtrl"), obj->GetPropertyAsString(_("name")));
		xrc.AddWindowProperties();
		return xrc.GetXrcObject();
	}

	ticpp::Element* ImportFromXrc(ticpp::Element* xrcObj) override {
		XrcToXfbFilter filter(xrcObj, _("wxMediaCtrl"));
		filter.AddWindowProperties();
		return filter.GetXfbObject();
	}
};
#endif

class TimerComponent : public ComponentBase
{
public:
};

#if wxVERSION_NUMBER >= 2904
class PropertyGridComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxPropertyGrid* pg = new wxPropertyGrid((wxWindow *)parent, wxID_ANY,
												obj->GetPropertyAsPoint(wxT("pos")),
												obj->GetPropertyAsSize(wxT("size")),
												obj->GetPropertyAsInteger(wxT("style")) |
												obj->GetPropertyAsInteger(wxT("window_style")) );

		if ( !obj->GetPropertyAsString(wxT("extra_style")).empty() )
		{
			pg->SetExtraStyle( obj->GetPropertyAsInteger( wxT("extra_style") ) );
		}

		return pg;
	}

	/*void Cleanup( wxObject* )
	{
		// Prevent assert for missing event handler
	}*/

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxPropertyGrid* pg = wxDynamicCast( wxobject, wxPropertyGrid);
		if ( NULL == pg )
		{
			// very very strange
			return;
		}

		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (childObj->GetClassName() == _("propGridItem"))
			{
				if (childObj->GetPropertyAsString( _("type") ) == _("Category") )
				{
					pg->Append( new wxPropertyCategory( childObj->GetPropertyAsString( _("label") ), childObj->GetPropertyAsString( _("label") ) ) );
				}
				else
				{
					wxPGProperty *prop = wxDynamicCast( wxCreateDynamicObject( wxT("wx") + (childObj->GetPropertyAsString( _("type") ) ) + wxT("Property") ), wxPGProperty );
					if( prop )
					{
						prop->SetLabel( childObj->GetPropertyAsString( _("label") ) );
						prop->SetName( childObj->GetPropertyAsString( _("label") ) );
						pg->Append( prop );

						if( childObj->GetPropertyAsString( _("help") ) != wxEmptyString )
						{
							pg->SetPropertyHelpString( prop, childObj->GetPropertyAsString( _("help") ) );
						}
					}
				}
			}
		}
	}
};

class PropertyGridManagerComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxPropertyGridManager* pgman = new wxPropertyGridManager((wxWindow *)parent, wxID_ANY,
																obj->GetPropertyAsPoint(wxT("pos")),
																obj->GetPropertyAsSize(wxT("size")),
																obj->GetPropertyAsInteger(wxT("style")) |
																obj->GetPropertyAsInteger(wxT("window_style")));

		if ( !obj->GetPropertyAsString( wxT("extra_style") ).empty() )
		{
			pgman->SetExtraStyle( obj->GetPropertyAsInteger( wxT("extra_style") ) );
		}

		pgman->ShowHeader(obj->GetPropertyAsInteger(wxT("show_header")) != 0);

		// Adding a page sets target page to the one added, so
		// we don't have to call SetTargetPage if we are filling
		// it right after adding.
		/*wxPropertyGridPage* pg = pgman->AddPage( _("First Page") );

		pg->Append( new wxPropertyCategory( _("Sample Category") ) );

		// Add string property
		wxPGProperty *id = pg->Append( new wxStringProperty( _("Label"), wxPG_LABEL, _("Initial Value") ) );
		pg->SetPropertyHelpString( id, _("A string property") );

		// Add int property
		pg->Append( new wxIntProperty ( wxT("IntProperty"), wxPG_LABEL, 12345678 ) );

		// Add float property (value type is actually double)
		pg->Append( new wxFloatProperty ( wxT("FloatProperty"), wxPG_LABEL, 12345.678 ) );

		// Add a bool property
		pg->Append( new wxBoolProperty ( wxT("BoolProperty"), wxPG_LABEL, false ) );
		pg->Append( new wxBoolProperty ( wxT("BoolPropertyAsCheckbox"), wxPG_LABEL, true ) );
		pg->SetPropertyAttribute( wxT("BoolPropertyAsCheckbox"), wxPG_BOOL_USE_CHECKBOX, (long)1 );

		// Add an enum property
		wxArrayString strings;
		strings.Add( _("Herbivore") );
		strings.Add( _("Carnivore") );
		strings.Add( _("Omnivore") );

		wxArrayInt indexes;
		indexes.Add( 0 );
		indexes.Add( 1 );
		indexes.Add( 2 );

		pg->Append( new wxEnumProperty( wxT("EnumProperty"), wxPG_LABEL, strings, indexes, 0 ) );

		pg->Append( new wxPropertyCategory( _("Low Priority Properties") ) );

		// A string property that can be edited in a separate editor dialog.
		pg->Append( new wxLongStringProperty( wxT("LongStringProperty"), wxPG_LABEL,
											  wxString(_("This is much longer string than the ") ) +
											  wxString(_("first one. Edit it by clicking the button.") ) ) );

		// String editor with dir selector button.
		pg->Append( new wxDirProperty( wxT("DirProperty"), wxPG_LABEL, ::wxGetUserHome() ) );

		// A file selector property.
		pg->Append( new wxFileProperty( wxT("FileProperty"), wxPG_LABEL, wxEmptyString ) );

		wxPropertyGridPage* pg2 = pgman->AddPage( _("Second Page") );

		pg2->Append( new wxPropertyCategory( _("Sample Parent Property"), wxPG_LABEL ) );

		wxPGProperty* carProp2 = pg2->Append( new wxStringProperty( _("Car"), wxPG_LABEL, wxT("<composed>") ) );
		pg2->AppendIn( carProp2, new wxStringProperty( _("Model"), wxPG_LABEL, wxT("Lamborghini Diablo SV") ) );
		pg2->AppendIn( carProp2, new wxIntProperty( _("Engine Size (cc)"), wxPG_LABEL, 5707) );

		wxPGProperty* speedsProp2 = pg2->AppendIn( carProp2, new wxStringProperty( _("Speeds"), wxPG_LABEL, wxT("<composed>") ) );
		pg2->AppendIn( speedsProp2, new wxIntProperty( _("Max. Speed (mph)"), wxPG_LABEL, 300 ) );
		pg2->AppendIn( speedsProp2, new wxFloatProperty( _("0-100 mph (sec)"), wxPG_LABEL, 3.9 ) );
		pg2->AppendIn( speedsProp2, new wxFloatProperty( _("1/4 mile (sec)"), wxPG_LABEL, 8.6) );

		pg2->AppendIn( carProp2, new wxIntProperty( _("Price ($)"), wxPG_LABEL, 300000 ) );

		if ( obj->GetPropertyAsInteger( wxT("include_advanced") ) )
		{
			pg2->Append( new wxPropertyCategory( _("Advanced Properties"), wxPG_LABEL ) );
			// wxArrayStringProperty embeds a wxArrayString.
			pg2->Append( new wxArrayStringProperty( _("Example of ArrayStringProperty"), wxT("ArrayStringProp") ) );

			// Image file property. Wildcard is auto-generated from available
			// image handlers, so it is not set this time.
			pg2->Append( new wxImageFileProperty( _("Example of ImageFileProperty"), wxT("ImageFileProp") ) );

			// Font property has sub-properties.
			pg2->Append( new wxFontProperty( _("Font"), wxPG_LABEL ) );

			// Colour property with arbitrary colour.
			pg2->Append( new wxColourProperty( _("My Colour 1"), wxPG_LABEL, wxColour( 242, 109, 0 ) ) );

			// System colour property.
			pg2->Append( new wxSystemColourProperty( _("My SysColour 1"), wxPG_LABEL, wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) ) );

			// System colour property with custom colour.
			pg2->Append( new wxSystemColourProperty( _("My SysColour 2"), wxPG_LABEL, wxColour( 0, 200, 160 ) ) );

			// Cursor property
			pg2->Append( new wxCursorProperty( _("My Cursor"), wxPG_LABEL, wxCURSOR_ARROW ) );
		}*/

		return pgman;
	}
/*
	void Cleanup( wxObject* )
	{
		// Prevent assert for missing event handler
	}*/

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxPropertyGridManager* pgm = wxDynamicCast( wxobject, wxPropertyGridManager);
		if ( NULL == pgm )
		{
			// very very strange
			return;
		}

		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (childObj->GetClassName() == _("propGridPage"))
			{
				wxPropertyGridPage *page = pgm->AddPage( childObj->GetPropertyAsString( _("label") ), childObj->GetPropertyAsBitmap( _("bitmap") ) );

				for( size_t j = 0; j < childObj->GetChildCount(); ++j )
				{
					IObject* innerChildObj = childObj->GetChildPtr( j );
					if (innerChildObj->GetClassName() == _("propGridItem"))
					{
						if (innerChildObj->GetPropertyAsString( _("type") ) == _("Category") )
						{
							page->Append( new wxPropertyCategory( innerChildObj->GetPropertyAsString( _("label") ), innerChildObj->GetPropertyAsString( _("label") ) ) );
						}
						else
						{
							wxPGProperty *prop = wxDynamicCast( wxCreateDynamicObject( wxT("wx") + (innerChildObj->GetPropertyAsString( _("type") ) ) + wxT("Property") ), wxPGProperty );
							if( prop )
							{
								prop->SetLabel( innerChildObj->GetPropertyAsString( _("label") ) );
								prop->SetName( innerChildObj->GetPropertyAsString( _("label") ) );
								page->Append( prop );

								if( innerChildObj->GetPropertyAsString( _("help") ) != wxEmptyString )
								{
									page->SetPropertyHelpString( prop, innerChildObj->GetPropertyAsString( _("help") ) );
								}
							}
						}
					}
				}
			}
		}

		if( count )
		{
			pgm->SelectPage( 0 );
		}

		pgm->Update();
	}
};

class PropertyGridItemComponent : public ComponentBase{};
class PropertyGridPageComponent : public ComponentBase{};

class StyledTextComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxStyledTextCtrl* m_code = new wxStyledTextCtrl( 	(wxWindow *)parent, wxID_ANY,
												obj->GetPropertyAsPoint(_("pos")),
												obj->GetPropertyAsSize(_("size")),
												obj->GetPropertyAsInteger(_("window_style")),
												obj->GetPropertyAsString(_("name"))
											);

		// Line Numbers
		if ( 0 != obj->GetPropertyAsInteger(_("line_numbers") ) )
		{
			m_code->SetMarginType( 0, wxSTC_MARGIN_NUMBER );
			m_code->SetMarginWidth( 0, m_code->TextWidth (wxSTC_STYLE_LINENUMBER, wxT("_99999"))  );
		}
		else
		{
			m_code->SetMarginWidth( 0, 0 );
		}

		// markers
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS);
		m_code->MarkerSetBackground (wxSTC_MARKNUM_FOLDER, wxColour (wxT("BLACK")));
		m_code->MarkerSetForeground (wxSTC_MARKNUM_FOLDER, wxColour (wxT("WHITE")));
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS);
		m_code->MarkerSetBackground (wxSTC_MARKNUM_FOLDEROPEN, wxColour (wxT("BLACK")));
		m_code->MarkerSetForeground (wxSTC_MARKNUM_FOLDEROPEN, wxColour (wxT("WHITE")));
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY);
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUS);
		m_code->MarkerSetBackground (wxSTC_MARKNUM_FOLDEREND, wxColour (wxT("BLACK")));
		m_code->MarkerSetForeground (wxSTC_MARKNUM_FOLDEREND, wxColour (wxT("WHITE")));
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUS);
		m_code->MarkerSetBackground (wxSTC_MARKNUM_FOLDEROPENMID, wxColour (wxT("BLACK")));
		m_code->MarkerSetForeground (wxSTC_MARKNUM_FOLDEROPENMID, wxColour (wxT("WHITE")));
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY);
		m_code->MarkerDefine (wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY);

		// folding
		if ( 0 != obj->GetPropertyAsInteger(_("folding") ) )
		{
			m_code->SetMarginType (1, wxSTC_MARGIN_SYMBOL);
			m_code->SetMarginMask (1, wxSTC_MASK_FOLDERS);
			m_code->SetMarginWidth (1, 16);
			m_code->SetMarginSensitive (1, true);

			m_code->SetProperty( wxT("fold"), wxT("1") );
			m_code->SetFoldFlags( wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED | wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED );
		}
		else
		{
			m_code->SetMarginWidth( 1, 0 );
		}
		m_code->SetIndentationGuides(obj->GetPropertyAsInteger(_("indentation_guides")));

		m_code->SetMarginWidth( 2, 0 );

		m_code->SetLexer(wxSTC_LEX_CPP);
		m_code->SetKeyWords(0, wxT("asm auto bool break case catch char class const const_cast \
							   continue default delete do double dynamic_cast else enum explicit \
							   export extern false float for friend goto if inline int long \
							   mutable namespace new operator private protected public register \
							   reinterpret_cast return short signed sizeof static static_cast \
							   struct switch template this throw true try typedef typeid \
							   typename union unsigned using virtual void volatile wchar_t \
							   while"));

		wxFont font(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
		if ( !obj->GetPropertyAsString(_("font")).empty() )
		{
			font = obj->GetPropertyAsFont(_("font"));
		}

		m_code->StyleSetFont(wxSTC_STYLE_DEFAULT, font );

		m_code->StyleClearAll();
		m_code->StyleSetBold(wxSTC_C_WORD, true);
		m_code->StyleSetForeground(wxSTC_C_WORD, *wxBLUE);
		m_code->StyleSetForeground(wxSTC_C_STRING, *wxRED);
		m_code->StyleSetForeground(wxSTC_C_STRINGEOL, *wxRED);
		m_code->StyleSetForeground(wxSTC_C_PREPROCESSOR, wxColour(49, 106, 197));
		m_code->StyleSetForeground(wxSTC_C_COMMENT, wxColour(0, 128, 0));
		m_code->StyleSetForeground(wxSTC_C_COMMENTLINE, wxColour(0, 128, 0));
		m_code->StyleSetForeground(wxSTC_C_COMMENTDOC, wxColour(0, 128, 0));
		m_code->StyleSetForeground(wxSTC_C_COMMENTLINEDOC, wxColour(0, 128, 0));
		m_code->StyleSetForeground(wxSTC_C_NUMBER, *wxBLUE );
		m_code->SetUseTabs( ( 0 != obj->GetPropertyAsInteger( _("use_tabs") ) ) );
		m_code->SetTabWidth( obj->GetPropertyAsInteger( _("tab_width") ) );
		m_code->SetTabIndents( ( 0 != obj->GetPropertyAsInteger( _("tab_indents") ) ) );
		m_code->SetBackSpaceUnIndents( ( 0 != obj->GetPropertyAsInteger( _("backspace_unindents") ) ) );
		m_code->SetIndent( obj->GetPropertyAsInteger( _("tab_width") ) );
		m_code->SetSelBackground(true, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
		m_code->SetSelForeground(true, wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
		m_code->SetViewEOL( ( 0 != obj->GetPropertyAsInteger( _("view_eol") ) ) );
		m_code->SetViewWhiteSpace(obj->GetPropertyAsInteger(_("view_whitespace")));

		m_code->SetCaretWidth(2);

		m_code->SetText( 	wxT( "/** Sample Class to Display wxScintilla */\n" )
							wxT( "class ScintillaSampleCode\n" )
							wxT( "{\n" )
							wxT( "private:\n" )
							wxT( "\tint m_privateMember;\n\n" )
							wxT( "public:\n\n" )
							wxT( "\t// Sample Member Function\n" )
							wxT( "\tint SampleFunction( int sample = 0 )\n" )
							wxT( "\t{\n" )
							wxT( "\t\treturn sample;\n" )
							wxT( "\t}\n" )
							wxT( "};\n" )
						);

		m_code->PushEventHandler( new ComponentEvtHandler( m_code, GetManager() ) );

		return m_code;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxStyledTextCtrl);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
};

void ComponentEvtHandler::OnMarginClick( wxStyledTextEvent& event )
{
	wxStyledTextCtrl* scintilla = wxDynamicCast( m_window, wxStyledTextCtrl );
	if ( scintilla != NULL )
	{
		if ( event.GetMargin() == 1 )
		{
			int lineClick = scintilla->LineFromPosition( event.GetPosition() );
			int levelClick = scintilla->GetFoldLevel( lineClick );
			if ( ( levelClick & wxSTC_FOLDLEVELHEADERFLAG ) > 0 )
			{
				scintilla->ToggleFold( lineClick );
			}
		}
	}
	event.Skip();
}

class DataViewModel : public wxDataViewModel
{
public:
	unsigned int GetChildren(const wxDataViewItem&,
	                         wxDataViewItemArray& /*children*/) const override {
		return 0;
	}
	unsigned int GetColumnCount() const override {
		return 0;
	}
	wxString GetColumnType(unsigned int /*col*/) const override {
		return wxVariant("Dummy").GetType();
	}
	wxDataViewItem GetParent(const wxDataViewItem&) const override {
		return wxDataViewItem( NULL );
	}
	bool IsContainer(const wxDataViewItem&) const override {
		return false;
	}
	void GetValue(wxVariant&, const wxDataViewItem&, unsigned int /*col*/) const override {
	}
	bool SetValue(const wxVariant&, const wxDataViewItem&, unsigned int /*col*/) override {
		return true;
	}
};

class DataViewCtrl : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxDataViewCtrl* dataViewCtrl = new wxDataViewCtrl((wxWindow *)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("window_style")));

			wxObjectDataPtr<DataViewModel> model;
			model = new DataViewModel;
			dataViewCtrl->AssociateModel( model.get() );

		return dataViewCtrl;
	}

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxDataViewCtrl* list = wxDynamicCast( wxobject, wxDataViewCtrl);
		if ( NULL == list )
		{
			// very very strange
			return;
		}
		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (childObj->GetClassName() == _("dataViewColumn"))
			{
				if (childObj->GetPropertyAsString( _("type")) == _("Text"))
				{
					auto* col = list->AppendTextColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Toggle"))
				{
					auto* col = list->AppendToggleColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Progress"))
				{
					auto* col = list->AppendProgressColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("IconText"))
				{
					auto* col = list->AppendIconTextColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Date"))
				{
					auto* col = list->AppendDateColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Bitmap"))
				{
					auto* col = list->AppendBitmapColumn(
						childObj->GetPropertyAsString(_("label")),
						childObj->GetPropertyAsInteger(_("model_column")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
			}
		}
	}
};


class DataViewTreeCtrl : public ComponentBase
{
public:
	wxObject* Create( IObject* obj, wxObject* parent ) override
	{
		wxDataViewTreeCtrl* dataViewTreeCtrl = new wxDataViewTreeCtrl((wxWindow *)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("window_style")));

		return dataViewTreeCtrl;
	}
};

class DataViewListCtrl : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxDataViewListCtrl* dataViewListCtrl = new wxDataViewListCtrl((wxWindow *)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("window_style")));

		return dataViewListCtrl;
	}

	void OnCreated( wxObject* wxobject, wxWindow* /*wxparent*/ ) override
	{
		wxDataViewListCtrl* list = wxDynamicCast( wxobject, wxDataViewListCtrl);
		if ( NULL == list )
		{
			// very very strange
			return;
		}
		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (childObj->GetClassName() == _("dataViewListColumn"))
			{
				if (childObj->GetPropertyAsString( _("type")) == _("Text"))
				{
					auto* col = list->AppendTextColumn(
						childObj->GetPropertyAsString(_("label")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Toggle"))
				{
					auto* col = list->AppendToggleColumn(
						childObj->GetPropertyAsString(_("label")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("Progress"))
				{
					auto* col = list->AppendProgressColumn(
						childObj->GetPropertyAsString(_("label")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
				else if (childObj->GetPropertyAsString( _("type")) == _("IconText"))
				{
					auto* col = list->AppendIconTextColumn(
						childObj->GetPropertyAsString(_("label")),
						static_cast<wxDataViewCellMode>(childObj->GetPropertyAsInteger(_("mode"))),
						childObj->GetPropertyAsInteger(_("width")),
						static_cast<wxAlignment>(childObj->GetPropertyAsInteger(_("align"))),
						childObj->GetPropertyAsInteger(_("flags"))
					);
					if (!childObj->IsNull(_("ellipsize")))
					{
						col->GetRenderer()->EnableEllipsize(static_cast<wxEllipsizeMode>(childObj->GetPropertyAsInteger(_("ellipsize"))));
					}
				}
			}
		}
	}
};

class DataViewListColumn : public ComponentBase{};

class DataViewColumn : public ComponentBase{};


///////////////////////////////////////////////////////////////////////////////
class wxcoreTreeListCtrlComponent : public ComponentBase
{
public:
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxTreeListCtrl* treeListCtrl = new wxTreeListCtrl( (wxWindow *)parent, wxID_ANY,
				obj->GetPropertyAsPoint(_("pos")),
				obj->GetPropertyAsSize(_("size")),
				obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style")));

		return treeListCtrl;
	}

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		// initialize tree
		wxTreeListCtrl* treeListCtrl = wxDynamicCast( wxobject, wxTreeListCtrl );
		int colCount = treeListCtrl->GetColumnCount();

		// Check for columns
		if ( 0 == colCount )
		{
			return;
		}

		wxTreeListItem root = treeListCtrl->GetRootItem();

		wxTreeListItem treeListParent;
		wxTreeListItem treeListItem;
		int n = 0;

		// Build tree.
		treeListItem = treeListCtrl->AppendItem( root, wxString::Format( _("Item #%d"), ++n ) );
		FillItem( treeListCtrl, treeListItem, colCount, n );

		treeListParent = treeListItem;
		for ( int i = 0; i < 5; ++i )
		{
			treeListItem = treeListCtrl->AppendItem( treeListParent, wxString::Format( _("Item #%d"), ++n ) );
			FillItem( treeListCtrl, treeListItem, colCount, n );
		}
		treeListCtrl->Expand( treeListParent );

		treeListParent = treeListItem;
		for ( int i = 0; i < 5; ++i )
		{
			treeListItem = treeListCtrl->AppendItem( treeListParent, wxString::Format( _("Item #%d"), ++n ) );
			FillItem( treeListCtrl, treeListItem, colCount, n );
		}
		treeListCtrl->Expand( treeListParent );
	}

	void FillItem( wxTreeListCtrl* treeListCtrl, wxTreeListItem itemId, int colCount, int row )
	{
		for ( int i = 0; i < colCount; ++i )
		{
			treeListCtrl->SetItemText( itemId, i, wxString::Format( _("Item #%d, column #%d" ), row, i ) );
		}
	}
};

class wxcoreTreeListCtrlColumnComponent : public ComponentBase
{
public:
	void OnCreated(wxObject* wxobject, wxWindow* wxparent) override {
		IObject* obj = GetManager()->GetIObject( wxobject );
		wxTreeListCtrl* treeList = wxDynamicCast( wxparent, wxTreeListCtrl );

		if ( !( obj && treeList ) )
		{
			wxLogError( _("wxcoreTreeListCtrlColumnComponent is missing its wxFormBuilder object(%i) or its parent(%i)"), obj,treeList );
			return;
		}

		treeList->AppendColumn( obj->GetPropertyAsString( _("name") ),
			obj->GetPropertyAsInteger( _("width") ),
			static_cast< wxAlignment >( obj->GetPropertyAsInteger( _("alignment") ) ),
			obj->GetPropertyAsInteger( _("flag") ) );
	}

	void OnSelected(wxObject*) override {
	}
};

class RibbonBarComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonBar *rb = new wxRibbonBar((wxWindow*)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))  );

		if( obj->GetPropertyAsString( _("theme"))  == _("Default"))
				rb->SetArtProvider( new wxRibbonDefaultArtProvider );
		else if( obj->GetPropertyAsString( _("theme"))  == _("Generic"))
				rb->SetArtProvider( new wxRibbonAUIArtProvider );
		else if( obj->GetPropertyAsString( _("theme"))  == _("MSW") )
				rb->SetArtProvider( new wxRibbonMSWArtProvider );

		rb->PushEventHandler( new ComponentEvtHandler( rb, GetManager() ) );

		return rb;
	}

	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonBar);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxRibbonBar* rb = wxDynamicCast( wxobject, wxRibbonBar );
		if ( NULL == rb )
		{
			// very very strange
			return;
		}

		rb->Realize();
	}
};

void ComponentEvtHandler::OnRibbonBarPageChanged( wxRibbonBarEvent& event )
{
	if ( m_window != event.GetEventObject() )
	{
		return;
	}

	wxRibbonBar *rb = wxDynamicCast( event.GetEventObject(), wxRibbonBar );
	if( rb == NULL )
	{
		return;
	}

	int selPage = rb->GetActivePage();

	size_t count = m_manager->GetChildCount( m_window );
	for ( size_t i = 0; i < count; i++ )
	{
		wxObject* wxChild = m_manager->GetChild( m_window, i );
		IObject*  iChild = m_manager->GetIObject( wxChild );
		if ( iChild )
		{
			if (int(i) == selPage && iChild->GetPropertyAsInteger(_("select")) == 0) {
				m_manager->ModifyProperty( wxChild, _("select"), wxT("1"), false );
			} else if (int(i) != selPage && iChild->GetPropertyAsInteger(_("select")) != 0) {
				m_manager->ModifyProperty( wxChild, _("select"), wxT("0"), false );
			}
		}
	}

	// Select the corresponding ribbon page in the object tree
	if ( NULL != rb )
	{
		m_manager->SelectObject( rb->GetPage( selPage ) );
	}
}

class RibbonPageComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonPage *rbpage = new wxRibbonPage((wxRibbonBar*)parent,
			wxID_ANY,
			obj->GetPropertyAsString(_("label")),
			obj->GetPropertyAsBitmap(_("bitmap")),
			0);

		if (obj->GetPropertyAsInteger(_("select")) != 0) {
			((wxRibbonBar*)parent)->SetActivePage(rbpage);
		}

		//rbpage->PushEventHandler( new ComponentEvtHandler( rbpage, GetManager() ) );

		return rbpage;
	}

	/*
	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonPage);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
	*/
};

class RibbonPanelComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonPanel *rbp = new wxRibbonPanel((wxRibbonPage*)parent,
			wxID_ANY,
			obj->GetPropertyAsString(_("label")),
			obj->GetPropertyAsBitmap(_("bitmap")),
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			obj->GetPropertyAsInteger(_("style")) | obj->GetPropertyAsInteger(_("window_style"))  );

		//rbp->PushEventHandler( new ComponentEvtHandler( rbp, GetManager() ) );

		return rbp;
	}

	/*
	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonPanel);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
	*/
};

class RibbonButtonBarComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonButtonBar *rbb = new wxRibbonButtonBar((wxRibbonPanel*)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			0);

		//rbb->PushEventHandler( new ComponentEvtHandler( rbb, GetManager() ) );

		return rbb;
	}

	/*
	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonButtonBar);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
	*/

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxRibbonButtonBar* rb = wxDynamicCast( wxobject, wxRibbonButtonBar );
		if ( NULL == rb )
		{
			// very very strange
			return;
		}

		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (childObj->GetClassName() == wxT("ribbonButton"))
			{
				rb->AddButton(wxID_ANY,
							childObj->GetPropertyAsString( _("label") ),
							childObj->GetPropertyAsBitmap( _("bitmap") ),
							childObj->GetPropertyAsString( _("help") ) );
			} else if (childObj->GetClassName() == wxT("ribbonDropdownButton"))
			{
				rb->AddDropdownButton(wxID_ANY,
									childObj->GetPropertyAsString( _("label") ),
									childObj->GetPropertyAsBitmap( _("bitmap") ),
									childObj->GetPropertyAsString( _("help") ) );
			} else if (childObj->GetClassName() == wxT("ribbonHybridButton"))
			{
				rb->AddHybridButton(wxID_ANY,
								childObj->GetPropertyAsString( _("label") ),
								childObj->GetPropertyAsBitmap( _("bitmap") ),
								childObj->GetPropertyAsString( _("help") ) );
			} else if (childObj->GetClassName() == wxT("ribbonToggleButton"))
			{
				rb->AddToggleButton(wxID_ANY,
									childObj->GetPropertyAsString( _("label") ),
									childObj->GetPropertyAsBitmap( _("bitmap") ),
									childObj->GetPropertyAsString( _("help") ) );
			}
		}
	}
};

class RibbonButtonComponent : public ComponentBase{};
class RibbonDropdownButtonComponent : public ComponentBase{};
class RibbonHybridButtonComponent : public ComponentBase{};
class RibbonToggleButtonComponent : public ComponentBase{};

class RibbonToolBarComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonToolBar *rbb = new wxRibbonToolBar((wxRibbonPanel*)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			0 );

		//rbb->PushEventHandler( new ComponentEvtHandler( rbb, GetManager() ) );

		return rbb;
	}

	/*
	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonToolBar);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
	*/

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxRibbonToolBar* rb = wxDynamicCast( wxobject, wxRibbonToolBar );
		if ( NULL == rb )
		{
			// very very strange
			return;
		}

		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if (wxT("ribbonTool") == childObj->GetClassName() )
			{
				rb->AddTool(wxID_ANY,
							childObj->GetPropertyAsBitmap( _("bitmap") ),
							childObj->GetPropertyAsString( _("help") ) );
			} else if (wxT("ribbonDropdownTool") == childObj->GetClassName() )
			{
				rb->AddDropdownTool(wxID_ANY,
									childObj->GetPropertyAsBitmap( _("bitmap") ),
									childObj->GetPropertyAsString( _("help") ) );
			} else if (wxT("ribbonHybridTool") == childObj->GetClassName() )
			{
				rb->AddHybridTool(wxID_ANY,
								childObj->GetPropertyAsBitmap( _("bitmap") ),
								childObj->GetPropertyAsString( _("help") ) );
			} else if (wxT("ribbonToggleTool") == childObj->GetClassName() )
			{
				rb->AddToggleTool(wxID_ANY,
								childObj->GetPropertyAsBitmap( _("bitmap") ),
								childObj->GetPropertyAsString( _("help") ) );

			}
		}
	}
};

class RibbonToolComponent : public ComponentBase{};
class RibbonDropdownToolComponent : public ComponentBase{};
class RibbonHybridToolComponent : public ComponentBase{};
class RibbonToggleToolComponent : public ComponentBase{};

class RibbonGalleryComponent : public ComponentBase
{
	wxObject* Create(IObject* obj, wxObject* parent) override {
		wxRibbonGallery *ribbonGallery = new wxRibbonGallery((wxRibbonPanel*)parent,
			wxID_ANY,
			obj->GetPropertyAsPoint(_("pos")),
			obj->GetPropertyAsSize(_("size")),
			0);

		//ribbonGallery->PushEventHandler( new ComponentEvtHandler( ribbonGallery, GetManager() ) );

		return ribbonGallery;
	}

	/*
	void Cleanup(wxObject* obj) override
	{
		auto* window = wxDynamicCast(obj, wxRibbonGallery);
		if (window)
		{
			window->PopEventHandler(true);
		}
	}
	*/

	void OnCreated(wxObject* wxobject, wxWindow* /*wxparent*/) override {
		wxRibbonGallery* rg = wxDynamicCast( wxobject, wxRibbonGallery );
		if ( NULL == rg )
		{
			// very very strange
			return;
		}

		size_t count = GetManager()->GetChildCount( wxobject );
		for ( size_t i = 0; i < count; ++i )
		{
			wxObject* child = GetManager()->GetChild( wxobject, i );
			IObject* childObj = GetManager()->GetIObject( child );
			if ( wxT("ribbonGalleryItem") == childObj->GetClassName() )
			{
				rg->Append(childObj->GetPropertyAsBitmap( _("bitmap") ), wxID_ANY );
			}
		}
	}
};

class RibbonGalleryItemComponent : public ComponentBase{};

#endif

///////////////////////////////////////////////////////////////////////////////

BEGIN_LIBRARY()

WINDOW_COMPONENT("wxCalendarCtrl",CalendarCtrlComponent)
WINDOW_COMPONENT("wxDatePickerCtrl",DatePickerCtrlComponent)
WINDOW_COMPONENT("wxTimePickerCtrl",TimePickerCtrlComponent)
WINDOW_COMPONENT("wxHtmlWindow", HtmlWindowComponent)
WINDOW_COMPONENT("wxToggleButton",ToggleButtonComponent)
WINDOW_COMPONENT("wxBitmapToggleButton",BitmapToggleButtonComponent)
WINDOW_COMPONENT("wxTreeCtrl",TreeCtrlComponent)
WINDOW_COMPONENT("wxGrid",GridComponent)
WINDOW_COMPONENT("wxScrollBar",ScrollBarComponent)
WINDOW_COMPONENT("wxSpinCtrl",SpinCtrlComponent)
WINDOW_COMPONENT("wxSpinButton",SpinButtonComponent)
WINDOW_COMPONENT("CustomControl", CustomControlComponent)
WINDOW_COMPONENT("wxDataViewCtrl", DataViewCtrl )
WINDOW_COMPONENT("wxDataViewTreeCtrl", DataViewTreeCtrl )
WINDOW_COMPONENT("wxDataViewListCtrl", DataViewListCtrl )
ABSTRACT_COMPONENT("dataViewListColumn", DataViewListColumn)
ABSTRACT_COMPONENT("dataViewColumn", DataViewColumn)
WINDOW_COMPONENT("wxRibbonBar", RibbonBarComponent)
WINDOW_COMPONENT("wxRibbonPage", RibbonPageComponent)
WINDOW_COMPONENT("wxRibbonPanel", RibbonPanelComponent)
WINDOW_COMPONENT("wxRibbonButtonBar", RibbonButtonBarComponent)
WINDOW_COMPONENT("wxRibbonToolBar", RibbonToolBarComponent)
WINDOW_COMPONENT("wxRibbonGallery", RibbonGalleryComponent)
ABSTRACT_COMPONENT("ribbonButton", RibbonButtonComponent)
ABSTRACT_COMPONENT("ribbonDropdownButton", RibbonDropdownButtonComponent)
ABSTRACT_COMPONENT("ribbonHybridButton", RibbonHybridButtonComponent)
ABSTRACT_COMPONENT("ribbonToggleButton", RibbonToggleButtonComponent)
ABSTRACT_COMPONENT("ribbonTool", RibbonToolComponent)
ABSTRACT_COMPONENT("ribbonDropdownTool", RibbonDropdownToolComponent)
ABSTRACT_COMPONENT("ribbonHybridTool", RibbonHybridToolComponent)
ABSTRACT_COMPONENT("ribbonToggleTool", RibbonToggleToolComponent)
ABSTRACT_COMPONENT("ribbonGalleryItem", RibbonGalleryItemComponent)

// wxCheckListBox
WINDOW_COMPONENT("wxCheckListBox",CheckListBoxComponent)

#ifdef USE_MEDIACTRL
WINDOW_COMPONENT("wxMediaCtrl",MediaCtrlComponent)
#endif

// wxRichTextCtrl
WINDOW_COMPONENT( "wxRichTextCtrl", RichTextCtrlComponent )
MACRO(wxTE_PROCESS_ENTER);
MACRO(wxTE_PROCESS_TAB);
MACRO(wxTE_READONLY);
MACRO(wxTE_AUTO_URL);

// wxColourPickerCtrl
WINDOW_COMPONENT("wxColourPickerCtrl", ColourPickerComponent)
MACRO(wxCLRP_DEFAULT_STYLE)
MACRO(wxCLRP_USE_TEXTCTRL)
MACRO(wxCLRP_SHOW_LABEL)

// wxFontPickerCtrl
WINDOW_COMPONENT("wxFontPickerCtrl", FontPickerComponent)
MACRO(wxFNTP_DEFAULT_STYLE)
MACRO(wxFNTP_USE_TEXTCTRL)
MACRO(wxFNTP_FONTDESC_AS_LABEL)
MACRO(wxFNTP_USEFONT_FOR_LABEL)

// wxFilePickerCtrl
WINDOW_COMPONENT("wxFilePickerCtrl", FilePickerComponent)
MACRO(wxFLP_DEFAULT_STYLE)
MACRO(wxFLP_USE_TEXTCTRL)
MACRO(wxFLP_OPEN)
MACRO(wxFLP_SAVE)
MACRO(wxFLP_OVERWRITE_PROMPT)
MACRO(wxFLP_FILE_MUST_EXIST)
MACRO(wxFLP_CHANGE_DIR)
MACRO(wxFLP_SMALL)

// wxDirPickerCtrl
WINDOW_COMPONENT("wxDirPickerCtrl", DirPickerComponent)
MACRO(wxDIRP_DEFAULT_STYLE)
MACRO(wxDIRP_USE_TEXTCTRL)
MACRO(wxDIRP_DIR_MUST_EXIST)
MACRO(wxDIRP_CHANGE_DIR)
MACRO(wxDIRP_SMALL)

// wxHyperlinkCtrl
WINDOW_COMPONENT("wxHyperlinkCtrl", HyperlinkComponent)
MACRO(wxHL_ALIGN_LEFT)
MACRO(wxHL_ALIGN_RIGHT)
MACRO(wxHL_ALIGN_CENTRE)
MACRO(wxHL_CONTEXTMENU)
MACRO(wxHL_DEFAULT_STYLE)

// wxSearchCtrl
WINDOW_COMPONENT("wxSearchCtrl", SearchCtrlComponent)
MACRO(wxTE_PROCESS_ENTER);
MACRO(wxTE_PROCESS_TAB);
MACRO(wxTE_NOHIDESEL);
MACRO(wxTE_LEFT);
MACRO(wxTE_CENTER);
MACRO(wxTE_RIGHT);
MACRO(wxTE_CAPITALIZE);

WINDOW_COMPONENT("wxSpinCtrlDouble",SpinCtrlDoubleComponent)

// wxCalendarCtrl
MACRO(wxCAL_SUNDAY_FIRST)
MACRO(wxCAL_MONDAY_FIRST)
MACRO(wxCAL_SHOW_HOLIDAYS)
MACRO(wxCAL_NO_YEAR_CHANGE)
MACRO(wxCAL_NO_MONTH_CHANGE)
MACRO(wxCAL_SHOW_SURROUNDING_WEEKS)
MACRO(wxCAL_SEQUENTIAL_MONTH_SELECTION)
MACRO(wxCAL_SHOW_WEEK_NUMBERS)

// wxDatePickerCtrl
MACRO(wxDP_SPIN)
MACRO(wxDP_DROPDOWN)
MACRO(wxDP_SHOWCENTURY)
MACRO(wxDP_ALLOWNONE)
MACRO(wxDP_DEFAULT)


// wxTimePickerCtrl
MACRO( wxTP_DEFAULT )


// wxHtmlWindow
MACRO(wxHW_SCROLLBAR_NEVER)
MACRO(wxHW_SCROLLBAR_AUTO)
MACRO(wxHW_NO_SELECTION)

// wxTreeCtrl
MACRO(wxTR_EDIT_LABELS)
MACRO(wxTR_NO_BUTTONS)
MACRO(wxTR_HAS_BUTTONS)
MACRO(wxTR_TWIST_BUTTONS)
MACRO(wxTR_NO_LINES)
MACRO(wxTR_FULL_ROW_HIGHLIGHT)
MACRO(wxTR_LINES_AT_ROOT)
MACRO(wxTR_HIDE_ROOT)
MACRO(wxTR_ROW_LINES)
MACRO(wxTR_HAS_VARIABLE_ROW_HEIGHT)
MACRO(wxTR_SINGLE)
MACRO(wxTR_MULTIPLE)
MACRO(wxTR_DEFAULT_STYLE)

// wxGrid
MACRO(wxALIGN_LEFT)
MACRO(wxALIGN_CENTER)
MACRO(wxALIGN_RIGHT)
MACRO(wxALIGN_TOP)
MACRO(wxALIGN_BOTTOM)

// wxScrollBar
MACRO(wxSB_HORIZONTAL)
MACRO(wxSB_VERTICAL)

// wxSpinCtrl and wxSpinButton
MACRO(wxSP_ARROW_KEYS)
MACRO(wxSP_WRAP)
MACRO(wxSP_HORIZONTAL)
MACRO(wxSP_VERTICAL)

// wxGenericDirCtrl
WINDOW_COMPONENT("wxGenericDirCtrl",GenericDirCtrlComponent)
MACRO(wxDIRCTRL_DIR_ONLY)
MACRO(wxDIRCTRL_3D_INTERNAL)
MACRO(wxDIRCTRL_SELECT_FIRST)
MACRO(wxDIRCTRL_EDIT_LABELS)
MACRO(wxDIRCTRL_MULTIPLE)

// wxTimer
ABSTRACT_COMPONENT("wxTimer", TimerComponent)

#if wxVERSION_NUMBER >= 2904
// wxPropertyGrid
WINDOW_COMPONENT("wxPropertyGrid", PropertyGridComponent)
ABSTRACT_COMPONENT("propGridItem", PropertyGridItemComponent)
MACRO(wxPG_DEFAULT_STYLE)
MACRO(wxPG_AUTO_SORT)
MACRO(wxPG_HIDE_CATEGORIES)
MACRO(wxPG_ALPHABETIC_MODE)
MACRO(wxPG_BOLD_MODIFIED)
MACRO(wxPG_SPLITTER_AUTO_CENTER)
MACRO(wxPG_TOOLTIPS)
MACRO(wxPG_HIDE_MARGIN)
MACRO(wxPG_STATIC_SPLITTER)
MACRO(wxPG_STATIC_LAYOUT)
MACRO(wxPG_LIMITED_EDITING)
MACRO(wxPG_EX_INIT_NOCAT)
MACRO(wxPG_EX_HELP_AS_TOOLTIPS)
MACRO(wxPG_EX_NATIVE_DOUBLE_BUFFERING)
MACRO(wxPG_EX_AUTO_UNSPECIFIED_VALUES)
MACRO(wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES)
MACRO(wxPG_EX_MULTIPLE_SELECTION)
MACRO(wxPG_EX_ENABLE_TLP_TRACKING)

// wxPropertyGridManager
WINDOW_COMPONENT("wxPropertyGridManager", PropertyGridManagerComponent)
ABSTRACT_COMPONENT("propGridPage", PropertyGridPageComponent)
MACRO(wxPG_EX_NO_FLAT_TOOLBAR)
MACRO(wxPG_EX_MODE_BUTTONS)
MACRO(wxPG_EX_HIDE_PAGE_BUTTONS)
MACRO(wxPG_EX_NO_TOOLBAR_DIVIDER)
MACRO(wxPG_EX_TOOLBAR_SEPARATOR)
MACRO(wxPGMAN_DEFAULT_STYLE)
MACRO(wxPG_DESCRIPTION)
MACRO(wxPG_TOOLBAR)
MACRO(wxPG_NO_INTERNAL_BORDER)

// wxStyledTextCtrl
WINDOW_COMPONENT("wxStyledTextCtrl", StyledTextComponent )

// wxDataViewCtrl
MACRO(wxDV_SINGLE)
MACRO(wxDV_MULTIPLE)
MACRO(wxDV_ROW_LINES)
MACRO(wxDV_HORIZ_RULES)
MACRO(wxDV_VERT_RULES)
MACRO(wxDV_VARIABLE_LINE_HEIGHT)
MACRO(wxDV_NO_HEADER)

MACRO(wxDATAVIEW_CELL_INERT)
MACRO(wxDATAVIEW_CELL_ACTIVATABLE)
MACRO(wxDATAVIEW_CELL_EDITABLE)

MACRO(wxDATAVIEW_COL_RESIZABLE)
MACRO(wxDATAVIEW_COL_SORTABLE)
MACRO(wxDATAVIEW_COL_REORDERABLE)
MACRO(wxDATAVIEW_COL_HIDDEN)

MACRO(wxELLIPSIZE_NONE)
MACRO(wxELLIPSIZE_START)
MACRO(wxELLIPSIZE_MIDDLE)
MACRO(wxELLIPSIZE_END)

MACRO(wxALIGN_LEFT)
MACRO(wxALIGN_TOP)
MACRO(wxALIGN_RIGHT)
MACRO(wxALIGN_BOTTOM)
MACRO(wxALIGN_CENTER)
MACRO(wxALIGN_CENTER_HORIZONTAL)
MACRO(wxALIGN_CENTER_VERTICAL)

// wxRibbonBar
MACRO(wxRIBBON_BAR_DEFAULT_STYLE)
MACRO(wxRIBBON_BAR_FOLDBAR_STYLE)
MACRO(wxRIBBON_BAR_SHOW_PAGE_LABELS)
MACRO(wxRIBBON_BAR_SHOW_PAGE_ICONS)
MACRO(wxRIBBON_BAR_FLOW_HORIZONTAL)
MACRO(wxRIBBON_BAR_FLOW_VERTICAL)
MACRO(wxRIBBON_BAR_SHOW_PANEL_EXT_BUTTONS)
MACRO(wxRIBBON_BAR_SHOW_PANEL_MINIMISE_BUTTONS)
MACRO(wxRIBBON_BAR_SHOW_TOGGLE_BUTTON)
MACRO(wxRIBBON_BAR_SHOW_HELP_BUTTON)

// wxRibbonPanel
MACRO(wxRIBBON_PANEL_DEFAULT_STYLE)
MACRO(wxRIBBON_PANEL_NO_AUTO_MINIMISE)
MACRO(wxRIBBON_PANEL_EXT_BUTTON)
MACRO(wxRIBBON_PANEL_MINIMISE_BUTTON)
MACRO(wxRIBBON_PANEL_STRETCH)
MACRO(wxRIBBON_PANEL_FLEXIBLE)
#endif


// wxTreeListCtrl
WINDOW_COMPONENT( "wxTreeListCtrl", wxcoreTreeListCtrlComponent )
MACRO(wxTL_SINGLE)
MACRO(wxTL_MULTIPLE)
MACRO(wxTL_CHECKBOX)
MACRO(wxTL_3STATE)
MACRO(wxTL_USER_3STATE)
MACRO(wxTR_DEFAULT_STYLE)

ABSTRACT_COMPONENT( "wxTreeListCtrlColumn", wxcoreTreeListCtrlColumnComponent )
MACRO(wxCOL_RESIZABLE)
MACRO(wxCOL_SORTABLE)
MACRO(wxCOL_REORDERABLE)
MACRO(wxCOL_HIDDEN)

END_LIBRARY()

